#include "SupervisedLearning.h"

SupervisedLearning::SupervisedLearning ()
{
	data = Mat();
	labels = Mat();
}

SupervisedLearning::SupervisedLearning (int numRows, int numCols)
{
	data = Mat_<float>(numRows,numCols);
	labels = Mat_<float>(numRows, 1);
	k = 17;
	numberOfAttributes = data.cols;
	numberOfElements = data.rows;
}

void SupervisedLearning::readData(string fdata)
{
	ifstream in(fdata);
	float value;
	if (in.is_open())
	{
		for (int i = 0; i < data.rows; i++)
		{
			for (int j = 0; j < data.cols; j++)
			{
				in >> value;
				data.at<float>(i,j) = value;
			}
		}
	}
}

void SupervisedLearning::readLabels(string flabels)
{
	ifstream in(flabels);
	string value;
	if (in.is_open())
	{
		for (int i = 0; i < data.rows; i++)
		{
			in >> value;
			if (value == "saudavel")
			{
				labels.at<float>(i,0) = 0;
			}
			else if (value == "doente")
			{
				labels.at<float>(i,0) = 1;
			}	
		}
	}
}

void SupervisedLearning::read(string fdata, string flabels)
{
	readData(fdata);
	readLabels(flabels);
}



Mat SupervisedLearning::getData()
{
	return data;
}
Mat SupervisedLearning::getLabels()
{
	return labels;
}

void SupervisedLearning::evaluate()
{
	eval.accur = MLEvaluation::accuracy(confusion);
	eval.precis = MLEvaluation::precision(confusion);
	eval.sensib = MLEvaluation::sensibility(confusion);
	eval.specif = MLEvaluation::specificity(confusion);
	eval.youd = MLEvaluation::youden(confusion);
	eval.roc = MLEvaluation::ROC(confusion);
}

void SupervisedLearning::printEvaluation()
{
	cout << "Accuracy: " << eval.accur << endl;
	cout << "precision: " << eval.precis << endl;
	cout << "sensibility: " << eval.sensib << endl;
	cout << "specificity: " << eval.specif << endl;
	cout << "Youden: " << eval.youd << endl;
	cout << "ROC: " << eval.roc << endl;
}

void SupervisedLearning::read(string fdata, string flabels, Mat v)
{
	int natt = countNumberOfAttributes(v);
	data = Mat_<float>(51, natt);
	ifstream in(fdata);
	float value;
	int count = 0;
	if (in.is_open())
	{
		for (int i = 0; i < numberOfElements; i++)
		{
			count = 0;
			for (int j = 0; j < numberOfAttributes; j++)
			{
				in >> value;
				if (v.at<int>(0,j) == 1)
				{
					data.at<float>(i,count++) = value;
				}
			}
		}
	}
	numberOfAttributes = natt;
	readLabels(flabels);
}

int SupervisedLearning::countNumberOfAttributes(Mat d)
{
	int cnt = 0;
	for (int i = 0; i < d.cols; i++)
	{
		if (d.at<int>(0,i) == 1)
		{
			cnt++;
		}
	}
	return cnt;
}

void SupervisedLearning::initializeGeneticAlgorithm(const int numberOfElements,
								   const int numberOfAttributes,
								   const int numberOfIterations,
								   const float percentOfLeaders,
								   const float percentOfMutants)
{
	this->numberOfElements = numberOfElements;
	this->numberOfAttributes = numberOfAttributes;
	this->numberOfIterations = numberOfIterations;
	this->percentOfLeaders = percentOfLeaders;
	this->percentOfMutants = percentOfLeaders;
}

vector<KeySort> SupervisedLearning::initializeVector(int n, int numOfAtt)
{
	vector<KeySort> v;
	for (int i = 0; i < n ; i++)
	{
		v.push_back(KeySort(numOfAtt));
	}
	return v;
}

vector<KeySort> SupervisedLearning::initializeElements()
{
	//vector<KeySort> elements(numberOfElements);
	//for (int i = 0; i < numberOfElements; i++)
	//{
	//	KeySort a = KeySort(numberOfAttributes);
	//	cout << a.key << endl << a.element << endl;
	//	elements(0,i) = a;
	//}
	vector<KeySort> elements = initializeVector(numberOfElements, numberOfAttributes);
	for (int i = 0; i < numberOfElements; i++)
	{
		for (int j = 0; j < numberOfAttributes; j++)
		{
			elements[i].key = 0;
			elements[i].element.at<int>(0,j) = (rand() % 2);
		}
	}
	return elements;
}

Mat SupervisedLearning::createDataMat(vector<KeySort> d, int n)
{
	int count = countNumberOfAttributes(d[n].element);
	Mat_<float> curr( getData().rows, count);

	for (int i = 0; i < getData().rows; i++)
	{
		int inc = 0;
		for (int j = 0; j < getData().cols; j++)
		{
			if (d[n].element.at<int>(0,j) == 1)
			{
				curr.at<float>(i,inc++) = getData().at<float>(i,j);
			}
		}
	}
	return curr;
}

Mat SupervisedLearning::createLabelsMat(vector<KeySort> data, int n)
{
	Mat_<float> curr( getLabels().rows, 1);
	for (int i = 0; i < getLabels().rows; i++)
	{
		curr.at<float>(i,0) = getLabels().at<float>(i,0);
	}
	return curr;
}

vector<KeySort> SupervisedLearning::crossOverAll(vector<KeySort>& elems)
{
	vector<KeySort> ret = initializeElements();
	int bests = percentOfLeaders/100.f * elems.size();
	for (int i = 0; i < bests; i++)
	{
		ret[i] = elems[i];
	}

	for (int i = 0; i < elems.size()-bests; i = i + 2)
	{
		Mat child1;
		Mat child2;
		crossOver(elems[i].element, elems[i+1].element, child1, child2);
		if (i+bests+1 < elems.size())
		{
			ret[i+bests].element = child1;
			ret[i+bests+1].element = child2;
		}

	}

	int mutation = percentOfMutants/100.f * elems.size();
	for (int i = 0 ; i < mutation; i++)
	{
		int randElement = rand() % elems.size();
		int randAttribute = rand() % elems[0].element.cols;
		if ( ret[randElement].element.at<int>(0,randAttribute) == 0)
		{
			ret[randElement].element.at<int>(0,randAttribute) = 1;
		}
		else
		{
			ret[randElement].element.at<int>(0,randAttribute) = 0;
		}
	}
	return ret;
}

void SupervisedLearning::crossOver(Mat& parent1, Mat& parent2, Mat& child1, Mat& child2)
{
	int random = rand() % parent1.cols;
	child1 = Mat_<int>(1,parent1.cols);
	child2 = Mat_<int>(1,parent1.cols);
	for (int i = 0; i < random; i++)
	{
		child1.at<int>(0,i) = parent1.at<int>(0,i);
		child2.at<int>(0,i) = parent2.at<int>(0,i);
	}
	for (int i = random; i < parent1.cols; i++)
	{
		child2.at<int>(0,i) = parent1.at<int>(0,i);
		child1.at<int>(0,i) = parent2.at<int>(0,i);
	}
}

void SupervisedLearning::plot (Mat dat)
{
	PCA pca (dat, Mat(), CV_PCA_DATA_AS_ROW , 2);
	
    // And copy the PCA results:
    Mat mean = pca.mean.clone();
    Mat eigenvalues = pca.eigenvalues.clone();
    Mat eigenvectors = pca.eigenvectors.clone();

	// The mean face:
	Mat nor = Mat();

	normalize (pca.project(dat), nor, 0, 255, NORM_MINMAX, CV_8U);
	cout << nor << endl;
	cout << nor.rows << endl;
	cout << nor.type() << endl;
	Mat img = Mat_<uchar>(255, 255);
	img = 255;
	for (int i = 0; i < nor.rows; i++)
	{
		if (getLabels().at<float>(i) == 1)
		{
			circle(img, Point(nor.at<uchar>(i,0),nor.at<uchar>(i,1)),3, Scalar(1,0,0),5);
		}
		else
		{
			rectangle(img,Point(nor.at<uchar>(i,0) - 5,nor.at<uchar>(i,1) - 5), Point(nor.at<uchar>(i,0) + 5,nor.at<uchar>(i,1) + 5),Scalar(0,0,0),1);
		}
	}
	imshow("avg", img);
	waitKey(0);


}